//
//  RACStreamVC.m
//  RACLearning
//
//  Created by 李阳 on 2018/6/7.
//  Copyright © 2018年 李阳. All rights reserved.
//

#import "RACStreamVC.h"


@interface RACStreamVC ()

@end

@implementation RACStreamVC

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
//    NSString *path = NSHomeDirectory();
    
}

- (void)buttonClicked
{
    [self zip];
}

#pragma mark - 常用操作方法

#pragma mark 其他操作

/*
 1. setKeyPath: onObject: nilValue:
 2. setKeyPath: onObject:
 */

#pragma mark 多线程操作

/*
 1. deliverOn:
 2. subscribeOn:
 3. deliverOnMainThread
 */

#pragma mark 副作用操作

/*
 1. doNext:
 2. doError:
 3. doCompleted:
 4. initially:
 5. finally:
 */



#pragma mark 同步操作

/*
 1. firstOrDefault: success: error:
 2. firstOrDefault:
 3. first
 4. waitUntilCompleted:
 5. toArray
 */


#pragma mark 高阶信号操作
// https://www.jianshu.com/p/d507e534dda0
/*
 1. flattenMap:
 2. flatten
 3. flatten:
 4. concat
 5. switchToLatest
 6. switch: cases: default:
 7. if: then: else:
 8. catch:
 9. catchTo:
 10. try:
 11. tryMap:
 12. timeout: onScheduler:
 */


#pragma mark 组合操作
// https://www.jianshu.com/p/707ece08257e
/*
 1. startWith:
 2. - concat:
 3. + concat:
 4. + merge:
 5. - merge:
 6. + zip:
 7. + zip: reduce:
 8. zipWith:
 9. combineLatestWith:
 10. combineLatest:
 11. combineLatest: reduce:
 12. combinePreviousWithStart: reduce:
 13. sample:
 */

- (void)zip
{
    RACSignal *signalD = [RACSignal interval:3 onScheduler:[RACScheduler mainThreadScheduler] withLeeway:0];
    RACSignal *signalO = [RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler] withLeeway:0];
    RACSignal *signalE = [RACSignal interval:4 onScheduler:[RACScheduler mainThreadScheduler] withLeeway:0];
    RACSignal *signalB = [RACSignal zip:@[signalD, signalO, signalE]];
    
    [signalB subscribeNext:^(id x) {
        NSLog(@"最后接收到的值 = %@",x);
    }];
}

- (void)combineLatest
{
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber)
                          {
                              [subscriber sendNext:@1];
                              [subscriber sendNext:@2];
                              [subscriber sendNext:@3];
                              [subscriber sendNext:@4];
                              [subscriber sendNext:@5];
                              [subscriber sendCompleted];
                              return [RACDisposable disposableWithBlock:^{
                                  NSLog(@"signalA dispose");
                              }];
                          }];
    
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber)
                          {
                              [subscriber sendNext:@"A"];
                              [subscriber sendNext:@"B"];
                              [subscriber sendNext:@"C"];
                              [subscriber sendNext:@"D"];
                              [subscriber sendCompleted];
                              return [RACDisposable disposableWithBlock:^{
                                  NSLog(@"signalB dispose");
                              }];
                          }];
    
    [[signalA combineLatestWith:signalB] subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
}


#pragma mark 过滤操作
// https://www.jianshu.com/p/707ece08257e
/*
 1. filter
 2. ignoreValues
 3. ignore:
 4. distinctUntilChanged
 5. take:
 6. takeLast:
 7. takeUntilBlock:
 8. takeWhileBlock:
 9. takeUntil:
 10. takeUntilReplacement:
 11. skip:
 12. skipUntilBlock:
 13. skipWhileBlock:
 14. groupBy:transform:
 15. groupBy:
 */
- (void)groupBy2
{
    // 简单算法题，分离数组中的相同的元素，如果元素个数大于2，则组成一个新的数组，结果得到多个包含相同元素的数组，
    // 例如[1,2,3,1,2,3]分离成[1,1],[2,2],[3,3]
    RACSignal *signal = @[@1, @2, @3, @4,@2,@3,@3,@4,@4,@4].rac_sequence.signal;
    
    NSArray * array = [[[[signal groupBy:^NSString *(NSNumber *object) {
        return [NSString stringWithFormat:@"%@",object];
    }] map:^id(RACGroupedSignal *value) {
        return [value sequence];
    }] sequence] map:^id(RACSignalSequence * value) {
        return value.array;
    }].array;
    
    for (NSNumber * num in array) {
        NSLog(@"最后的数组%@",num);
    }
    
    // 最后输出 [1,2,3,4,2,3,3,4,4,4]变成[1],[2,2],[3,3,3],[4,4,4,4]
}

- (void)groupBy1
{
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber)
                          {
                              [subscriber sendNext:@1];
                              [subscriber sendNext:@2];
                              [subscriber sendNext:@3];
                              [subscriber sendNext:@4];
                              [subscriber sendNext:@5];
                              [subscriber sendCompleted];
                              return [RACDisposable disposableWithBlock:^{
                                  NSLog(@"signalA dispose");
                              }];
                          }];
    
    RACSignal *signalGroup = [signalA groupBy:^id<NSCopying>(NSNumber *object) {
        return object.integerValue > 3 ? @"good" : @"bad";
    } transform:^id(NSNumber * object) {
        return @(object.integerValue * 10);
    }];
    
    [[[signalGroup filter:^BOOL(RACGroupedSignal *value) {
        return [(NSString *)value.key isEqualToString:@"good"];
    }] flatten] subscribeNext:^(id x) {
        NSLog(@"subscribeNext: %@", x);
    }];
    
}


#pragma mark 时间操作
// https://www.jianshu.com/p/9c4459ae71c5
/*
 1. throttle:valuesPassingTest:
 2. throttle:
 3. bufferWithTime:onScheduler:
 4. delay:
 5. interval:onScheduler:withLeeway:
 6. interval:onScheduler:
 */


#pragma mark 变换操作
// https://www.jianshu.com/p/9c4459ae71c5
/*
 1.map:
 2.mapReplace:
 3.reduceEach:
 4. reduceApply
 5. materialize
 6. dematerialize
 7. not
 8. and
 9. or
 10. any:
 11. any
 12. all:
 13. repeat
 14. retry:
 15. retry
 16. scanWithStart: reduceWithIndex:
 17. scanWithStart: reduce:
 18. aggregateWithStart: reduceWithIndex:
 19. aggregateWithStart: reduce:
 20. aggregateWithStartFactory: reduce:
 21. collect
 */



- (void)reduceApply
{
    RACSignal *signalA = [RACSignal createSignal:
                          ^RACDisposable *(id<RACSubscriber> subscriber)
                          {
                              id block = ^id(NSNumber *first,NSNumber *second,NSNumber *third)
                              {
                                  return @(first.integerValue + second.integerValue * third.integerValue);
                              };
                              
                              [subscriber sendNext:RACTuplePack(block,@2 , @3 , @8)];
                              [subscriber sendNext:RACTuplePack((id)(^id(NSNumber *x){return @(x.intValue * 10);}),@9,@10,@30)];
                              
                              [subscriber sendCompleted];
                              return [RACDisposable disposableWithBlock:^{
                                  NSLog(@"signal dispose");
                              }];
                          }];
    
    RACSignal *signalB = [signalA reduceApply];
    
    [signalB subscribeNext:^(id x) {
        NSLog(@"reduceApply %@", x);
    }];
}

- (void)or
{
    
    RACSubject *subject = [RACSubject subject];
    
    RACSignal *or = [subject or];
    
    [or subscribeNext:^(id x) {
        NSLog(@"any %@", x);
    }];
    
    [subject sendNext:RACTuplePack(@0, @0, @1)];
    
    [subject sendNext:RACTuplePack(@0)];
}

- (void)reduceEach
{
    // reduceEach就是每个信号内部都聚合在一起
    
    // 1. 创建信号
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        // 4. 发送信号
        [subscriber sendNext:RACTuplePack(@"5", @2, @"3")];
//        [subscriber sendNext:@"1 8"];
//        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"signal dispose");
        }];
    }];
    
    RACSignal *reduceEach = [signal1 reduceEach:^id(NSNumber *num1, NSNumber *num2){
        return @(num1.intValue + num2.intValue);
    }];
    
    [reduceEach subscribeNext:^(id x) {
        NSLog(@"reduceEach %@", x);
    }];
}

- (void)zipWith
{
    // 把两个信号通过zipWith之后，拉链的两边被中间的拉索拉到了一起。既然是拉链，那么一一的位置是有对应的，上面的拉链第一个位置只能对着下面拉链第一个位置，这样拉链才能拉到一起去。
    
    // 1. 创建信号
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        // 4. 发送信号
        [subscriber sendNext:@"1 1"];
        [subscriber sendNext:@"1 8"];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"signal dispose");
        }];
    }];
    
    // 1. 创建源信号
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        // 4. 发送源信号
        [subscriber sendNext:@"2 2"];
        [subscriber sendNext:@"2 3"];
        [subscriber sendNext:@"2 6"];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"signals dispose");
        }];
    }];
    
    RACSignal *zipSignal = [signal1 zipWith:signal2];
    
    [zipSignal subscribeNext:^(id x) {
        NSLog(@"concat signal next: %@", x);
    }];
}

- (void)concat
{
    //concat操作就是把两个信号合并起来。注意合并有先后顺序。
    
    // 1. 创建信号
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        // 4. 发送信号
        [subscriber sendNext:@"1 1"];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"signal1 dispose");
        }];
    }];
    
    // 1. 创建源信号
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        // 4. 发送源信号
        [subscriber sendNext:@"2 2"];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"signal2 dispose");
        }];
    }];
    
    RACSignal *concatSignal = [signal1 concat:signal2];
    
    [concatSignal subscribeNext:^(id x) {
        NSLog(@"concat signal next: %@", x);
    } error:^(NSError *error) {
        NSLog(@"concat signal error: %@", error);
    } completed:^{
        NSLog(@"concat signal completed");
    }];
}

- (void)map
{
    // map 映射方法的实质就是 bind 方法的深度封装，实际的信号流的流程还是以 bind为核心，只是巧妙的做了一些逻辑处理而已。
    
    // 1. 创建源信号
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        // 4. 发送源信号
        [subscriber sendNext:@"发送数据"];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"dispose");
        }];
    }];
    
    RACSignal *mapSignal = [signal map:^id(id value) {
        return [NSString stringWithFormat:@"%@ 6666", value];
    }];
    
    RACSignal *mapReplaceS = [signal mapReplace:@1];
    [mapReplaceS subscribeNext:^(id x) {
        NSLog(@"mapReplace: %@", x);
    }];
    
    [mapSignal subscribeNext:^(id x) {
        NSLog(@"map: %@", x);
    }];
}

- (void)bind
{
    // bind操作方法实质上就是生成新的绑定信号，利用returnSignal作为中间信号来改变源数据生成新的数据并执行新绑定信号的nextBlock代码块
    
    // 1. 创建源信号
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        // 4. 发送源信号
        [subscriber sendNext:@"发送数据"];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"dispose");
        }];
    }];
    
    // 2. 绑定源信号，生成绑定信号
    RACSignal *bindSignal = [signal bind:^RACStreamBindBlock{
        return ^(id value, BOOL *stop)
        {
            return [RACReturnSignal return:[NSString stringWithFormat:@"%@ 666", value]];
        };
    }];
    
    // 3. 订阅绑定信号
    [bindSignal subscribeNext:^(id x) {
        NSLog(@"next: %@", x);
    }];
}


#pragma mark - 常见类



- (void)RACCommand
{
    // 1. 创建命令
    RACCommand *command = [[RACCommand alloc]initWithSignalBlock:^RACSignal *(id input) {
        // 1.1 命令中包含的信号
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@"发送数据"];
            [subscriber sendCompleted];
            return [RACDisposable disposableWithBlock:^{
                NSLog(@"dispose");
            }];
        }];
    }];
    
    // 2. 订阅命令发出的信号
    [command.executionSignals.switchToLatest subscribeNext:^(id x) {
        NSLog(@"next: %@", x);
    }];
    
    // 3. 判断命令是否正在执行
    [command.executing subscribeNext:^(id x) {
        NSLog(@"命令在执行? %@", x);
    }];
    
    // 4. 执行命令
    [command execute:@"执行命令"];
}



- (void)RACSubject
{
    // 1. 创建信号
    RACSubject *subject = [RACSubject subject];
    // 2. 订阅信号
    [subject subscribeNext:^(id x) {
        NSLog(@"next: %@", x);
    }];
    // 3. 发送信号
    [subject sendNext:@"发送数据"];
}


- (void)RACMulticastConnection {
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSLog(@"发送请求");
        [subscriber sendNext:@"获取到数据"];
        return nil;
    }];
    
    RACMulticastConnection *connection = [signal publish];
    signal = connection.signal;
    
    [signal subscribeNext:^(id x) {
        NSLog(@"1%@", x);
    }];
    [signal subscribeNext:^(id x) {
        NSLog(@"2%@", x);
    }];
    
    [connection connect];
    
}

- (void)RACSignal
{
    // 1. 创建Signal
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 3. 发送next信号
        [subscriber sendNext:@"发送数据"];
        // 3.1 发送完成信号，并取消订阅
        [subscriber sendCompleted];
        // 4. 用于取消订阅时清理资源，比如释放一些资源
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"dispose");
        }];
    }];
    
    // 2.1 订阅next信号
    /*
     next: 发送数据
     dispose
     */
    [signal subscribeNext:^(id x) {
        NSLog(@"next1: %@",x);
    }];
    
    [signal subscribeNext:^(id x) {
        NSLog(@"next2: %@",x);
    }];
    
    // 2.2 订阅error信号
    /*
     dispose
     */
    [signal subscribeError:^(NSError *error) {
        NSLog(@"error: %@", error);
    }];

    // 2.3 订阅完成信号
    /*
     completed
     dispose
     */
    [signal subscribeCompleted:^{
        NSLog(@"completed");
    }];
}

@end
